home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / fileutils_3_3.lha / fileutils-3.3 / lib / getdate.y < prev    next >
Text File  |  1992-08-01  |  22KB  |  932 lines

  1. %{
  2. /* $Revision: 2.1 $
  3. **
  4. **  Originally written by Steven M. Bellovin <smb@research.att.com> while
  5. **  at the University of North Carolina at Chapel Hill.  Later tweaked by
  6. **  a couple of people on Usenet.  Completely overhauled by Rich $alz
  7. **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  8. **  send any email to Rich.
  9. **
  10. **  This grammar has eight shift/reduce conflicts.
  11. **
  12. **  This code is in the public domain and has no copyright.
  13. */
  14. /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
  15. /* SUPPRESS 288 on yyerrlab *//* Label unused */
  16.  
  17. #ifdef __GNUC__
  18. #define alloca __builtin_alloca
  19. #else
  20. #ifdef sparc
  21. #include <alloca.h>
  22. #else
  23. #ifdef _AIX /* for Bison */
  24.  #pragma alloca
  25. #else
  26. char *alloca ();
  27. #endif
  28. #endif
  29. #endif
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33.  
  34. #if    defined(vms)
  35. #include <types.h>
  36. #include <time.h>
  37. #else
  38. #include <sys/types.h>
  39. #if    defined(USG) || !defined(HAVE_FTIME)
  40. /*
  41. **  If you need to do a tzset() call to set the
  42. **  timezone, and don't have ftime().
  43. */
  44. struct timeb {
  45.     time_t        time;        /* Seconds since the epoch    */
  46.     unsigned short    millitm;    /* Field not used        */
  47.     short        timezone;
  48.     short        dstflag;    /* Field not used        */
  49. };
  50. #else
  51. #include <sys/timeb.h>
  52. #endif    /* defined(USG) || defined(FTIME_MISSING) */
  53. #if    defined(BSD4_2) || defined(BSD4_1C)
  54. #include <sys/time.h>
  55. #else
  56. #include <time.h>
  57. #endif    /* defined(BSD4_2) */
  58. #endif    /* defined(vms) */
  59.  
  60. #if defined (STDC_HEADERS) || defined (USG)
  61. #include <string.h>
  62. #endif
  63.  
  64. #if sgi
  65. #undef timezone
  66. #endif
  67.  
  68. extern struct tm    *localtime();
  69.  
  70. #define yyparse getdate_yyparse
  71. #define yylex getdate_yylex
  72. #define yyerror getdate_yyerror
  73.  
  74. #if    !defined(lint) && !defined(SABER)
  75. static char RCS[] =
  76.     "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
  77. #endif    /* !defined(lint) && !defined(SABER) */
  78.  
  79.  
  80. #define EPOCH        1970
  81. #define HOUR(x)        ((time_t)(x) * 60)
  82. #define SECSPERDAY    (24L * 60L * 60L)
  83.  
  84.  
  85. /*
  86. **  An entry in the lexical lookup table.
  87. */
  88. typedef struct _TABLE {
  89.     char    *name;
  90.     int        type;
  91.     time_t    value;
  92. } TABLE;
  93.  
  94.  
  95. /*
  96. **  Daylight-savings mode:  on, off, or not yet known.
  97. */
  98. typedef enum _DSTMODE {
  99.     DSTon, DSToff, DSTmaybe
  100. } DSTMODE;
  101.  
  102. /*
  103. **  Meridian:  am, pm, or 24-hour style.
  104. */
  105. typedef enum _MERIDIAN {
  106.     MERam, MERpm, MER24
  107. } MERIDIAN;
  108.  
  109.  
  110. /*
  111. **  Global variables.  We could get rid of most of these by using a good
  112. **  union as the yacc stack.  (This routine was originally written before
  113. **  yacc had the %union construct.)  Maybe someday; right now we only use
  114. **  the %union very rarely.
  115. */
  116. static char    *yyInput;
  117. static DSTMODE    yyDSTmode;
  118. static time_t    yyDayOrdinal;
  119. static time_t    yyDayNumber;
  120. static int    yyHaveDate;
  121. static int    yyHaveDay;
  122. static int    yyHaveRel;
  123. static int    yyHaveTime;
  124. static int    yyHaveZone;
  125. static time_t    yyTimezone;
  126. static time_t    yyDay;
  127. static time_t    yyHour;
  128. static time_t    yyMinutes;
  129. static time_t    yyMonth;
  130. static time_t    yySeconds;
  131. static time_t    yyYear;
  132. static MERIDIAN    yyMeridian;
  133. static time_t    yyRelMonth;
  134. static time_t    yyRelSeconds;
  135.  
  136. %}
  137.  
  138. %union {
  139.     time_t        Number;
  140.     enum _MERIDIAN    Meridian;
  141. }
  142.  
  143. %token    tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  144. %token    tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  145.  
  146. %type    <Number>    tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  147. %type    <Number>    tSEC_UNIT tSNUMBER tUNUMBER tZONE
  148. %type    <Meridian>    tMERIDIAN o_merid
  149.  
  150. %%
  151.  
  152. spec    : /* NULL */
  153.     | spec item
  154.     ;
  155.  
  156. item    : time {
  157.         yyHaveTime++;
  158.     }
  159.     | zone {
  160.         yyHaveZone++;
  161.     }
  162.     | date {
  163.         yyHaveDate++;
  164.     }
  165.     | day {
  166.         yyHaveDay++;
  167.     }
  168.     | rel {
  169.         yyHaveRel++;
  170.     }
  171.     | number
  172.     ;
  173.  
  174. time    : tUNUMBER tMERIDIAN {
  175.         yyHour = $1;
  176.         yyMinutes = 0;
  177.         yySeconds = 0;
  178.         yyMeridian = $2;
  179.     }
  180.     | tUNUMBER ':' tUNUMBER o_merid {
  181.         yyHour = $1;
  182.         yyMinutes = $3;
  183.         yySeconds = 0;
  184.         yyMeridian = $4;
  185.     }
  186.     | tUNUMBER ':' tUNUMBER tSNUMBER {
  187.         yyHour = $1;
  188.         yyMinutes = $3;
  189.         yyMeridian = MER24;
  190.         yyDSTmode = DSToff;
  191.         yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  192.     }
  193.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  194.         yyHour = $1;
  195.         yyMinutes = $3;
  196.         yySeconds = $5;
  197.         yyMeridian = $6;
  198.     }
  199.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  200.         yyHour = $1;
  201.         yyMinutes = $3;
  202.         yySeconds = $5;
  203.         yyMeridian = MER24;
  204.         yyDSTmode = DSToff;
  205.         yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  206.     }
  207.     ;
  208.  
  209. zone    : tZONE {
  210.         yyTimezone = $1;
  211.         yyDSTmode = DSToff;
  212.     }
  213.     | tDAYZONE {
  214.         yyTimezone = $1;
  215.         yyDSTmode = DSTon;
  216.     }
  217.     |
  218.       tZONE tDST {
  219.         yyTimezone = $1;
  220.         yyDSTmode = DSTon;
  221.     }
  222.     ;
  223.  
  224. day    : tDAY {
  225.         yyDayOrdinal = 1;
  226.         yyDayNumber = $1;
  227.     }
  228.     | tDAY ',' {
  229.         yyDayOrdinal = 1;
  230.         yyDayNumber = $1;
  231.     }
  232.     | tUNUMBER tDAY {
  233.         yyDayOrdinal = $1;
  234.         yyDayNumber = $2;
  235.     }
  236.     ;
  237.  
  238. date    : tUNUMBER '/' tUNUMBER {
  239.         yyMonth = $1;
  240.         yyDay = $3;
  241.     }
  242.     | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  243.         yyMonth = $1;
  244.         yyDay = $3;
  245.         yyYear = $5;
  246.     }
  247.     | tUNUMBER tSNUMBER tSNUMBER {
  248.         /* ISO 8601 format.  yyyy-mm-dd.  */
  249.         yyYear = $1;
  250.         yyMonth = -$2;
  251.         yyDay = -$3;
  252.     }
  253.     | tMONTH tUNUMBER {
  254.         yyMonth = $1;
  255.         yyDay = $2;
  256.     }
  257.     | tMONTH tUNUMBER ',' tUNUMBER {
  258.         yyMonth = $1;
  259.         yyDay = $2;
  260.         yyYear = $4;
  261.     }
  262.     | tUNUMBER tMONTH {
  263.         yyMonth = $2;
  264.         yyDay = $1;
  265.     }
  266.     | tUNUMBER tMONTH tUNUMBER {
  267.         yyMonth = $2;
  268.         yyDay = $1;
  269.         yyYear = $3;
  270.     }
  271.     ;
  272.  
  273. rel    : relunit tAGO {
  274.         yyRelSeconds = -yyRelSeconds;
  275.         yyRelMonth = -yyRelMonth;
  276.     }
  277.     | relunit
  278.     ;
  279.  
  280. relunit    : tUNUMBER tMINUTE_UNIT {
  281.         yyRelSeconds += $1 * $2 * 60L;
  282.     }
  283.     | tSNUMBER tMINUTE_UNIT {
  284.         yyRelSeconds += $1 * $2 * 60L;
  285.     }
  286.     | tMINUTE_UNIT {
  287.         yyRelSeconds += $1 * 60L;
  288.     }
  289.     | tSNUMBER tSEC_UNIT {
  290.         yyRelSeconds += $1;
  291.     }
  292.     | tUNUMBER tSEC_UNIT {
  293.         yyRelSeconds += $1;
  294.     }
  295.     | tSEC_UNIT {
  296.         yyRelSeconds++;
  297.     }
  298.     | tSNUMBER tMONTH_UNIT {
  299.         yyRelMonth += $1 * $2;
  300.     }
  301.     | tUNUMBER tMONTH_UNIT {
  302.         yyRelMonth += $1 * $2;
  303.     }
  304.     | tMONTH_UNIT {
  305.         yyRelMonth += $1;
  306.     }
  307.     ;
  308.  
  309. number    : tUNUMBER {
  310.         if (yyHaveTime && yyHaveDate && !yyHaveRel)
  311.         yyYear = $1;
  312.         else {
  313.         if($1>10000) {
  314.             time_t date_part;
  315.  
  316.             date_part= $1/10000;
  317.             yyHaveDate++;
  318.             yyDay= (date_part)%100;
  319.             yyMonth= (date_part/100)%100;
  320.             yyYear = date_part/10000;
  321.         } 
  322.             yyHaveTime++;
  323.         if ($1 < 100) {
  324.             yyHour = $1;
  325.             yyMinutes = 0;
  326.         }
  327.         else {
  328.             yyHour = $1 / 100;
  329.             yyMinutes = $1 % 100;
  330.         }
  331.         yySeconds = 0;
  332.         yyMeridian = MER24;
  333.         }
  334.     }
  335.     ;
  336.  
  337. o_merid    : /* NULL */ {
  338.         $$ = MER24;
  339.     }
  340.     | tMERIDIAN {
  341.         $$ = $1;
  342.     }
  343.     ;
  344.  
  345. %%
  346.  
  347. /* Month and day table. */
  348. static TABLE    MonthDayTable[] = {
  349.     { "january",    tMONTH,  1 },
  350.     { "february",    tMONTH,  2 },
  351.     { "march",        tMONTH,  3 },
  352.     { "april",        tMONTH,  4 },
  353.     { "may",        tMONTH,  5 },
  354.     { "june",        tMONTH,  6 },
  355.     { "july",        tMONTH,  7 },
  356.     { "august",        tMONTH,  8 },
  357.     { "september",    tMONTH,  9 },
  358.     { "sept",        tMONTH,  9 },
  359.     { "october",    tMONTH, 10 },
  360.     { "november",    tMONTH, 11 },
  361.     { "december",    tMONTH, 12 },
  362.     { "sunday",        tDAY, 0 },
  363.     { "monday",        tDAY, 1 },
  364.     { "tuesday",    tDAY, 2 },
  365.     { "tues",        tDAY, 2 },
  366.     { "wednesday",    tDAY, 3 },
  367.     { "wednes",        tDAY, 3 },
  368.     { "thursday",    tDAY, 4 },
  369.     { "thur",        tDAY, 4 },
  370.     { "thurs",        tDAY, 4 },
  371.     { "friday",        tDAY, 5 },
  372.     { "saturday",    tDAY, 6 },
  373.     { NULL }
  374. };
  375.  
  376. /* Time units table. */
  377. static TABLE    UnitsTable[] = {
  378.     { "year",        tMONTH_UNIT,    12 },
  379.     { "month",        tMONTH_UNIT,    1 },
  380.     { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  381.     { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  382.     { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  383.     { "hour",        tMINUTE_UNIT,    60 },
  384.     { "minute",        tMINUTE_UNIT,    1 },
  385.     { "min",        tMINUTE_UNIT,    1 },
  386.     { "second",        tSEC_UNIT,    1 },
  387.     { "sec",        tSEC_UNIT,    1 },
  388.     { NULL }
  389. };
  390.  
  391. /* Assorted relative-time words. */
  392. static TABLE    OtherTable[] = {
  393.     { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  394.     { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  395.     { "today",        tMINUTE_UNIT,    0 },
  396.     { "now",        tMINUTE_UNIT,    0 },
  397.     { "last",        tUNUMBER,    -1 },
  398.     { "this",        tMINUTE_UNIT,    0 },
  399.     { "next",        tUNUMBER,    2 },
  400.     { "first",        tUNUMBER,    1 },
  401. /*  { "second",        tUNUMBER,    2 }, */
  402.     { "third",        tUNUMBER,    3 },
  403.     { "fourth",        tUNUMBER,    4 },
  404.     { "fifth",        tUNUMBER,    5 },
  405.     { "sixth",        tUNUMBER,    6 },
  406.     { "seventh",    tUNUMBER,    7 },
  407.     { "eighth",        tUNUMBER,    8 },
  408.     { "ninth",        tUNUMBER,    9 },
  409.     { "tenth",        tUNUMBER,    10 },
  410.     { "eleventh",    tUNUMBER,    11 },
  411.     { "twelfth",    tUNUMBER,    12 },
  412.     { "ago",        tAGO,    1 },
  413.     { NULL }
  414. };
  415.  
  416. /* The timezone table. */
  417. /* Some of these are commented out because a time_t can't store a float. */
  418. static TABLE    TimezoneTable[] = {
  419.     { "gmt",    tZONE,     HOUR( 0) },    /* Greenwich Mean */
  420.     { "ut",    tZONE,     HOUR( 0) },    /* Universal (Coordinated) */
  421.     { "utc",    tZONE,     HOUR( 0) },
  422.     { "wet",    tZONE,     HOUR( 0) },    /* Western European */
  423.     { "bst",    tDAYZONE,  HOUR( 0) },    /* British Summer */
  424.     { "wat",    tZONE,     HOUR( 1) },    /* West Africa */
  425.     { "at",    tZONE,     HOUR( 2) },    /* Azores */
  426. #if    0
  427.     /* For completeness.  BST is also British Summer, and GST is
  428.      * also Guam Standard. */
  429.     { "bst",    tZONE,     HOUR( 3) },    /* Brazil Standard */
  430.     { "gst",    tZONE,     HOUR( 3) },    /* Greenland Standard */
  431. #endif
  432. #if 0
  433.     { "nft",    tZONE,     HOUR(3.5) },    /* Newfoundland */
  434.     { "nst",    tZONE,     HOUR(3.5) },    /* Newfoundland Standard */
  435.     { "ndt",    tDAYZONE,  HOUR(3.5) },    /* Newfoundland Daylight */
  436. #endif
  437.     { "ast",    tZONE,     HOUR( 4) },    /* Atlantic Standard */
  438.     { "adt",    tDAYZONE,  HOUR( 4) },    /* Atlantic Daylight */
  439.     { "est",    tZONE,     HOUR( 5) },    /* Eastern Standard */
  440.     { "edt",    tDAYZONE,  HOUR( 5) },    /* Eastern Daylight */
  441.     { "cst",    tZONE,     HOUR( 6) },    /* Central Standard */
  442.     { "cdt",    tDAYZONE,  HOUR( 6) },    /* Central Daylight */
  443.     { "mst",    tZONE,     HOUR( 7) },    /* Mountain Standard */
  444.     { "mdt",    tDAYZONE,  HOUR( 7) },    /* Mountain Daylight */
  445.     { "pst",    tZONE,     HOUR( 8) },    /* Pacific Standard */
  446.     { "pdt",    tDAYZONE,  HOUR( 8) },    /* Pacific Daylight */
  447.     { "yst",    tZONE,     HOUR( 9) },    /* Yukon Standard */
  448.     { "ydt",    tDAYZONE,  HOUR( 9) },    /* Yukon Daylight */
  449.     { "hst",    tZONE,     HOUR(10) },    /* Hawaii Standard */
  450.     { "hdt",    tDAYZONE,  HOUR(10) },    /* Hawaii Daylight */
  451.     { "cat",    tZONE,     HOUR(10) },    /* Central Alaska */
  452.     { "ahst",    tZONE,     HOUR(10) },    /* Alaska-Hawaii Standard */
  453.     { "nt",    tZONE,     HOUR(11) },    /* Nome */
  454.     { "idlw",    tZONE,     HOUR(12) },    /* International Date Line West */
  455.     { "cet",    tZONE,     -HOUR(1) },    /* Central European */
  456.     { "met",    tZONE,     -HOUR(1) },    /* Middle European */
  457.     { "mewt",    tZONE,     -HOUR(1) },    /* Middle European Winter */
  458.     { "mest",    tDAYZONE,  -HOUR(1) },    /* Middle European Summer */
  459.     { "swt",    tZONE,     -HOUR(1) },    /* Swedish Winter */
  460.     { "sst",    tDAYZONE,  -HOUR(1) },    /* Swedish Summer */
  461.     { "fwt",    tZONE,     -HOUR(1) },    /* French Winter */
  462.     { "fst",    tDAYZONE,  -HOUR(1) },    /* French Summer */
  463.     { "eet",    tZONE,     -HOUR(2) },    /* Eastern Europe, USSR Zone 1 */
  464.     { "bt",    tZONE,     -HOUR(3) },    /* Baghdad, USSR Zone 2 */
  465. #if 0
  466.     { "it",    tZONE,     -HOUR(3.5) },/* Iran */
  467. #endif
  468.     { "zp4",    tZONE,     -HOUR(4) },    /* USSR Zone 3 */
  469.     { "zp5",    tZONE,     -HOUR(5) },    /* USSR Zone 4 */
  470. #if 0
  471.     { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
  472. #endif
  473.     { "zp6",    tZONE,     -HOUR(6) },    /* USSR Zone 5 */
  474. #if    0
  475.     /* For completeness.  NST is also Newfoundland Stanard, and SST is
  476.      * also Swedish Summer. */
  477.     { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
  478.     { "sst",    tZONE,     -HOUR(7) },    /* South Sumatra, USSR Zone 6 */
  479. #endif    /* 0 */
  480.     { "wast",    tZONE,     -HOUR(7) },    /* West Australian Standard */
  481.     { "wadt",    tDAYZONE,  -HOUR(7) },    /* West Australian Daylight */
  482. #if 0
  483.     { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  484. #endif
  485.     { "cct",    tZONE,     -HOUR(8) },    /* China Coast, USSR Zone 7 */
  486.     { "jst",    tZONE,     -HOUR(9) },    /* Japan Standard, USSR Zone 8 */
  487. #if 0
  488.     { "cast",    tZONE,     -HOUR(9.5) },/* Central Australian Standard */
  489.     { "cadt",    tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
  490. #endif
  491.     { "east",    tZONE,     -HOUR(10) },    /* Eastern Australian Standard */
  492.     { "eadt",    tDAYZONE,  -HOUR(10) },    /* Eastern Australian Daylight */
  493.     { "gst",    tZONE,     -HOUR(10) },    /* Guam Standard, USSR Zone 9 */
  494.     { "nzt",    tZONE,     -HOUR(12) },    /* New Zealand */
  495.     { "nzst",    tZONE,     -HOUR(12) },    /* New Zealand Standard */
  496.     { "nzdt",    tDAYZONE,  -HOUR(12) },    /* New Zealand Daylight */
  497.     { "idle",    tZONE,     -HOUR(12) },    /* International Date Line East */
  498.     {  NULL  }
  499. };
  500.  
  501. /* Military timezone table. */
  502. static TABLE    MilitaryTable[] = {
  503.     { "a",    tZONE,    HOUR(  1) },
  504.     { "b",    tZONE,    HOUR(  2) },
  505.     { "c",    tZONE,    HOUR(  3) },
  506.     { "d",    tZONE,    HOUR(  4) },
  507.     { "e",    tZONE,    HOUR(  5) },
  508.     { "f",    tZONE,    HOUR(  6) },
  509.     { "g",    tZONE,    HOUR(  7) },
  510.     { "h",    tZONE,    HOUR(  8) },
  511.     { "i",    tZONE,    HOUR(  9) },
  512.     { "k",    tZONE,    HOUR( 10) },
  513.     { "l",    tZONE,    HOUR( 11) },
  514.     { "m",    tZONE,    HOUR( 12) },
  515.     { "n",    tZONE,    HOUR(- 1) },
  516.     { "o",    tZONE,    HOUR(- 2) },
  517.     { "p",    tZONE,    HOUR(- 3) },
  518.     { "q",    tZONE,    HOUR(- 4) },
  519.     { "r",    tZONE,    HOUR(- 5) },
  520.     { "s",    tZONE,    HOUR(- 6) },
  521.     { "t",    tZONE,    HOUR(- 7) },
  522.     { "u",    tZONE,    HOUR(- 8) },
  523.     { "v",    tZONE,    HOUR(- 9) },
  524.     { "w",    tZONE,    HOUR(-10) },
  525.     { "x",    tZONE,    HOUR(-11) },
  526.     { "y",    tZONE,    HOUR(-12) },
  527.     { "z",    tZONE,    HOUR(  0) },
  528.     { NULL }
  529. };
  530.  
  531.  
  532.  
  533.  
  534. /* ARGSUSED */
  535. int
  536. yyerror(s)
  537.     char    *s;
  538. {
  539.   return 0;
  540. }
  541.  
  542.  
  543. static time_t
  544. ToSeconds(Hours, Minutes, Seconds, Meridian)
  545.     time_t    Hours;
  546.     time_t    Minutes;
  547.     time_t    Seconds;
  548.     MERIDIAN    Meridian;
  549. {
  550.     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  551.     return -1;
  552.     switch (Meridian) {
  553.     case MER24:
  554.     if (Hours < 0 || Hours > 23)
  555.         return -1;
  556.     return (Hours * 60L + Minutes) * 60L + Seconds;
  557.     case MERam:
  558.     if (Hours < 1 || Hours > 12)
  559.         return -1;
  560.     return (Hours * 60L + Minutes) * 60L + Seconds;
  561.     case MERpm:
  562.     if (Hours < 1 || Hours > 12)
  563.         return -1;
  564.     return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  565.     }
  566.     /* NOTREACHED */
  567. }
  568.  
  569.  
  570. static time_t
  571. Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  572.     time_t    Month;
  573.     time_t    Day;
  574.     time_t    Year;
  575.     time_t    Hours;
  576.     time_t    Minutes;
  577.     time_t    Seconds;
  578.     MERIDIAN    Meridian;
  579.     DSTMODE    DSTmode;
  580. {
  581.     static int    DaysInMonth[12] = {
  582.     31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  583.     };
  584.     time_t    tod;
  585.     time_t    Julian;
  586.     int        i;
  587.  
  588.     if (Year < 0)
  589.     Year = -Year;
  590.     if (Year < 100)
  591.     Year += 1900;
  592.     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  593.             ? 29 : 28;
  594.     if (Year < EPOCH || Year > 1999
  595.      || Month < 1 || Month > 12
  596.      /* Lint fluff:  "conversion from long may lose accuracy" */
  597.      || Day < 1 || Day > DaysInMonth[(int)--Month])
  598.     return -1;
  599.  
  600.     for (Julian = Day - 1, i = 0; i < Month; i++)
  601.     Julian += DaysInMonth[i];
  602.     for (i = EPOCH; i < Year; i++)
  603.     Julian += 365 + (i % 4 == 0);
  604.     Julian *= SECSPERDAY;
  605.     Julian += yyTimezone * 60L;
  606.     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  607.     return -1;
  608.     Julian += tod;
  609.     if (DSTmode == DSTon
  610.      || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
  611.     Julian -= 60 * 60;
  612.     return Julian;
  613. }
  614.  
  615.  
  616. static time_t
  617. DSTcorrect(Start, Future)
  618.     time_t    Start;
  619.     time_t    Future;
  620. {
  621.     time_t    StartDay;
  622.     time_t    FutureDay;
  623.  
  624.     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  625.     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  626.     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  627. }
  628.  
  629.  
  630. static time_t
  631. RelativeDate(Start, DayOrdinal, DayNumber)
  632.     time_t    Start;
  633.     time_t    DayOrdinal;
  634.     time_t    DayNumber;
  635. {
  636.     struct tm    *tm;
  637.     time_t    now;
  638.  
  639.     now = Start;
  640.     tm = localtime(&now);
  641.     now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  642.     now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  643.     return DSTcorrect(Start, now);
  644. }
  645.  
  646.  
  647. static time_t
  648. RelativeMonth(Start, RelMonth)
  649.     time_t    Start;
  650.     time_t    RelMonth;
  651. {
  652.     struct tm    *tm;
  653.     time_t    Month;
  654.     time_t    Year;
  655.  
  656.     if (RelMonth == 0)
  657.     return 0;
  658.     tm = localtime(&Start);
  659.     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  660.     Year = Month / 12;
  661.     Month = Month % 12 + 1;
  662.     return DSTcorrect(Start,
  663.         Convert(Month, (time_t)tm->tm_mday, Year,
  664.         (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  665.         MER24, DSTmaybe));
  666. }
  667.  
  668.  
  669. static int
  670. LookupWord(buff)
  671.     char        *buff;
  672. {
  673.     register char    *p;
  674.     register char    *q;
  675.     register TABLE    *tp;
  676.     int            i;
  677.     int            abbrev;
  678.  
  679.     /* Make it lowercase. */
  680.     for (p = buff; *p; p++)
  681.     if (isupper(*p))
  682.         *p = tolower(*p);
  683.  
  684.     if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  685.     yylval.Meridian = MERam;
  686.     return tMERIDIAN;
  687.     }
  688.     if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  689.     yylval.Meridian = MERpm;
  690.     return tMERIDIAN;
  691.     }
  692.  
  693.     /* See if we have an abbreviation for a month. */
  694.     if (strlen(buff) == 3)
  695.     abbrev = 1;
  696.     else if (strlen(buff) == 4 && buff[3] == '.') {
  697.     abbrev = 1;
  698.     buff[3] = '\0';
  699.     }
  700.     else
  701.     abbrev = 0;
  702.  
  703.     for (tp = MonthDayTable; tp->name; tp++) {
  704.     if (abbrev) {
  705.         if (strncmp(buff, tp->name, 3) == 0) {
  706.         yylval.Number = tp->value;
  707.         return tp->type;
  708.         }
  709.     }
  710.     else if (strcmp(buff, tp->name) == 0) {
  711.         yylval.Number = tp->value;
  712.         return tp->type;
  713.     }
  714.     }
  715.  
  716.     for (tp = TimezoneTable; tp->name; tp++)
  717.     if (strcmp(buff, tp->name) == 0) {
  718.         yylval.Number = tp->value;
  719.         return tp->type;
  720.     }
  721.  
  722.     if (strcmp(buff, "dst") == 0) 
  723.     return tDST;
  724.  
  725.     for (tp = UnitsTable; tp->name; tp++)
  726.     if (strcmp(buff, tp->name) == 0) {
  727.         yylval.Number = tp->value;
  728.         return tp->type;
  729.     }
  730.  
  731.     /* Strip off any plural and try the units table again. */
  732.     i = strlen(buff) - 1;
  733.     if (buff[i] == 's') {
  734.     buff[i] = '\0';
  735.     for (tp = UnitsTable; tp->name; tp++)
  736.         if (strcmp(buff, tp->name) == 0) {
  737.         yylval.Number = tp->value;
  738.         return tp->type;
  739.         }
  740.     buff[i] = 's';        /* Put back for "this" in OtherTable. */
  741.     }
  742.  
  743.     for (tp = OtherTable; tp->name; tp++)
  744.     if (strcmp(buff, tp->name) == 0) {
  745.         yylval.Number = tp->value;
  746.         return tp->type;
  747.     }
  748.  
  749.     /* Military timezones. */
  750.     if (buff[1] == '\0' && isalpha(*buff)) {
  751.     for (tp = MilitaryTable; tp->name; tp++)
  752.         if (strcmp(buff, tp->name) == 0) {
  753.         yylval.Number = tp->value;
  754.         return tp->type;
  755.         }
  756.     }
  757.  
  758.     /* Drop out any periods and try the timezone table again. */
  759.     for (i = 0, p = q = buff; *q; q++)
  760.     if (*q != '.')
  761.         *p++ = *q;
  762.     else
  763.         i++;
  764.     *p = '\0';
  765.     if (i)
  766.     for (tp = TimezoneTable; tp->name; tp++)
  767.         if (strcmp(buff, tp->name) == 0) {
  768.         yylval.Number = tp->value;
  769.         return tp->type;
  770.         }
  771.  
  772.     return tID;
  773. }
  774.  
  775.  
  776. int
  777. yylex()
  778. {
  779.     register char    c;
  780.     register char    *p;
  781.     char        buff[20];
  782.     int            Count;
  783.     int            sign;
  784.  
  785.     for ( ; ; ) {
  786.     while (isspace(*yyInput))
  787.         yyInput++;
  788.  
  789.     if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  790.         if (c == '-' || c == '+') {
  791.         sign = c == '-' ? -1 : 1;
  792.         if (!isdigit(*++yyInput))
  793.             /* skip the '-' sign */
  794.             continue;
  795.         }
  796.         else
  797.         sign = 0;
  798.         for (yylval.Number = 0; isdigit(c = *yyInput++); )
  799.         yylval.Number = 10 * yylval.Number + c - '0';
  800.         yyInput--;
  801.         if (sign < 0)
  802.         yylval.Number = -yylval.Number;
  803.         return sign ? tSNUMBER : tUNUMBER;
  804.     }
  805.     if (isalpha(c)) {
  806.         for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  807.         if (p < &buff[sizeof buff - 1])
  808.             *p++ = c;
  809.         *p = '\0';
  810.         yyInput--;
  811.         return LookupWord(buff);
  812.     }
  813.     if (c != '(')
  814.         return *yyInput++;
  815.     Count = 0;
  816.     do {
  817.         c = *yyInput++;
  818.         if (c == '\0')
  819.         return c;
  820.         if (c == '(')
  821.         Count++;
  822.         else if (c == ')')
  823.         Count--;
  824.     } while (Count > 0);
  825.     }
  826. }
  827.  
  828.  
  829. time_t
  830. get_date(p, now)
  831.     char        *p;
  832.     struct timeb    *now;
  833. {
  834.     struct tm        *tm;
  835.     struct timeb    ftz;
  836.     time_t        Start;
  837.     time_t        tod;
  838. #if    !defined(HAVE_FTIME)
  839.     extern time_t    timezone;
  840. #endif    
  841.  
  842.     yyInput = p;
  843.     if (now == NULL) {
  844.     now = &ftz;
  845. #if    !defined(HAVE_FTIME)
  846.     (void)time(&ftz.time);
  847.     /* Set the timezone global. */
  848.     tzset();
  849. #if sgi
  850.     ftz.timezone = (int) _timezone / 60;
  851. #else
  852.     ftz.timezone = (int) timezone / 60;
  853. #endif    
  854. #else
  855.     (void)ftime(&ftz);
  856. #endif    /* HAVE_FTIME */
  857.     }
  858.  
  859.     tm = localtime(&now->time);
  860.     yyYear = tm->tm_year;
  861.     yyMonth = tm->tm_mon + 1;
  862.     yyDay = tm->tm_mday;
  863.     yyTimezone = now->timezone;
  864.     yyDSTmode = DSTmaybe;
  865.     yyHour = 0;
  866.     yyMinutes = 0;
  867.     yySeconds = 0;
  868.     yyMeridian = MER24;
  869.     yyRelSeconds = 0;
  870.     yyRelMonth = 0;
  871.     yyHaveDate = 0;
  872.     yyHaveDay = 0;
  873.     yyHaveRel = 0;
  874.     yyHaveTime = 0;
  875.     yyHaveZone = 0;
  876.  
  877.     if (yyparse()
  878.      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  879.     return -1;
  880.  
  881.     if (yyHaveDate || yyHaveTime || yyHaveDay) {
  882.     Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  883.             yyMeridian, yyDSTmode);
  884.     if (Start < 0)
  885.         return -1;
  886.     }
  887.     else {
  888.     Start = now->time;
  889.     if (!yyHaveRel)
  890.         Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  891.     }
  892.  
  893.     Start += yyRelSeconds;
  894.     Start += RelativeMonth(Start, yyRelMonth);
  895.  
  896.     if (yyHaveDay && !yyHaveDate) {
  897.     tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  898.     Start += tod;
  899.     }
  900.  
  901.     /* Have to do *something* with a legitimate -1 so it's distinguishable
  902.      * from the error return value.  (Alternately could set errno on error.) */
  903.     return Start == -1 ? 0 : Start;
  904. }
  905.  
  906.  
  907. #if    defined(TEST)
  908.  
  909. /* ARGSUSED */
  910. main(ac, av)
  911.     int        ac;
  912.     char    *av[];
  913. {
  914.     char    buff[128];
  915.     time_t    d;
  916.  
  917.     (void)printf("Enter date, or blank line to exit.\n\t> ");
  918.     (void)fflush(stdout);
  919.     while (gets(buff) && buff[0]) {
  920.     d = get_date(buff, (struct timeb *)NULL);
  921.     if (d == -1)
  922.         (void)printf("Bad format - couldn't convert.\n");
  923.     else
  924.         (void)printf("%s", ctime(&d));
  925.     (void)printf("\t> ");
  926.     (void)fflush(stdout);
  927.     }
  928.     exit(0);
  929.     /* NOTREACHED */
  930. }
  931. #endif    /* defined(TEST) */
  932.